home *** CD-ROM | disk | FTP | other *** search
/ MacGames Sampler / PHT MacGames Bundle.iso / MacSource Folder / Samples from the CD / C and C++ / Gnuplot 3.5 for Macintosh / SOURCES 3.5 / graphics_2.c < prev    next >
Text File  |  1993-11-12  |  56KB  |  2,086 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: graphics.c%v 3.50.1.9 1993/08/05 05:38:59 woo Exp $";
  3. #endif
  4.  
  5.  
  6. /* GNUPLOT - graphics.c */
  7. /*
  8.  * Copyright (C) 1986 - 1993   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted, 
  12.  * provided that the above copyright notice appear in all copies and 
  13.  * that both that copyright notice and this permission notice appear 
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *  
  20.  * This software is provided "as is" without express or implied warranty.
  21.  * 
  22.  *
  23.  * AUTHORS
  24.  * 
  25.  *   Original Software:
  26.  *     Thomas Williams,  Colin Kelley.
  27.  * 
  28.  *   Gnuplot 2.0 additions:
  29.  *       Russell Lang, Dave Kotz, John Campbell.
  30.  *
  31.  *   Gnuplot 3.0 additions:
  32.  *       Gershon Elber and many others.
  33.  *
  34.  * There is a mailing list for gnuplot users. Note, however, that the
  35.  * newsgroup 
  36.  *    comp.graphics.gnuplot 
  37.  * is identical to the mailing list (they
  38.  * both carry the same set of messages). We prefer that you read the
  39.  * messages through that newsgroup, to subscribing to the mailing list.
  40.  * (If you can read that newsgroup, and are already on the mailing list,
  41.  * please send a message info-gnuplot-request@dartmouth.edu, asking to be
  42.  * removed from the mailing list.)
  43.  *
  44.  * The address for mailing to list members is
  45.  *       info-gnuplot@dartmouth.edu
  46.  * and for mailing administrative requests is 
  47.  *       info-gnuplot-request@dartmouth.edu
  48.  * The mailing list for bug reports is 
  49.  *       bug-gnuplot@dartmouth.edu
  50.  * The list of those interested in beta-test versions is
  51.  *       info-gnuplot-beta@dartmouth.edu
  52.  */
  53.  
  54. #ifdef THINK_C
  55. #define THINK_C_2
  56. #endif
  57.  
  58. #include <stdio.h>
  59. #include <math.h>
  60. #include <assert.h>
  61. #if !defined(u3b2)
  62. #include <time.h>
  63. #endif
  64. #include "plot.h"
  65. #ifdef THINK_C
  66. #include "tout_protos.h"
  67. #endif
  68. #include "setshow.h"
  69.  
  70. #if defined(DJGPP)||defined(sun386)
  71. #define time_t unsigned long
  72. #endif
  73.  
  74. #ifndef AMIGA_SC_6_1
  75. extern char *strcpy(),*strncpy(),*strcat(),*ctime();
  76. #endif /* !AMIGA_SC_6_1 */
  77.  
  78. #if defined(THINK_C_1)
  79. char *tdate;
  80. #elif defined(THINK_C_2)
  81. extern char *tdate;
  82. #else
  83. char *tdate;
  84. #endif
  85.  
  86. #ifdef AMIGA_AC_5
  87. time_t dated;
  88. #else
  89. #if defined(apollo) || defined(sequent) || defined(u3b2) || defined(alliant) || defined(sun386)
  90. #include <sys/types.h> /* typedef long time_t; */
  91. #endif
  92.  
  93. #include <time.h>
  94.  
  95. #if defined(THINK_C_1)
  96. time_t dated;
  97. #elif defined(THINK_C_2)
  98. extern time_t dated;
  99. #else
  100. time_t dated; /* ,time(); */
  101. #endif
  102.  
  103.  
  104.  
  105. #endif
  106.  
  107. void plot_impulses();
  108. void plot_lines();
  109. void plot_points();
  110. void plot_dots();
  111. void plot_bars();
  112. void plot_boxes();
  113. void edge_intersect();
  114. TBOOLEAN two_edge_intersect();
  115.  
  116. void plot_steps();            /* JG */
  117. void edge_intersect_steps();         /* JG */
  118. TBOOLEAN two_edge_intersect_steps();    /* JG */
  119.  
  120. /* for plotting error bars */
  121. #define ERRORBARTIC (t->h_tic/2) /* half the width of error bar tic mark */
  122.  
  123. #ifndef max        /* Lattice C has max() in math.h, but shouldn't! */
  124. #define max(a,b) ((a > b) ? a : b)
  125. #endif
  126.  
  127. #ifndef min
  128. #define min(a,b) ((a < b) ? a : b)
  129. #endif
  130.  
  131. #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  132.  
  133. /* True if a and b have the same sign or zero (positive or negative) */
  134. #define samesign(a,b) ((a) * (b) >= 0)
  135.  
  136. /* Define the boundary of the plot
  137.  * These are computed at each call to do_plot, and are constant over
  138.  * the period of one do_plot. They actually only change when the term
  139.  * type changes and when the 'set size' factors change. 
  140.  */
  141. #if defined(THINK_C_1)
  142. extern int xleft, xright, ybot, ytop;
  143. #elif defined(THINK_C_2)
  144. extern int xleft, xright, ybot, ytop;
  145. #else
  146. static int xleft, xright, ybot, ytop;
  147. #endif
  148.  
  149. /* Boundary and scale factors, in user coordinates */
  150. /* x_min, x_max, y_min, y_max are local to this file and
  151.  * are not the same as variables of the same names in other files
  152.  */
  153. #if defined(THINK_C_1)
  154. double x_min, x_max, y_min, y_max;
  155. double xscale, yscale;
  156. #elif defined(THINK_C_2)
  157. extern double x_min, x_max, y_min, y_max;
  158. extern double xscale, yscale;
  159. #else
  160. static double x_min, x_max, y_min, y_max;
  161. static double xscale, yscale;
  162. #endif
  163.  
  164. /* And the functions to map from user to terminal coordinates */
  165. #define map_x(x) (int)(xleft+(x-x_min)*xscale+0.5) /* maps floating point x to screen */ 
  166. #define map_y(y) (int)(ybot+(y-y_min)*yscale+0.5)    /* same for y */
  167.  
  168. /* (DFK) Watch for cancellation error near zero on axes labels */
  169. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  170. #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  171. #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  172.  
  173. /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  174.  * macro, so I write it as a function on that machine.
  175.  */
  176. #ifndef sun386
  177. /* (DFK) Use 10^x if logscale is in effect, else x */
  178. #define CheckLog(is_log, base_log, x) ((is_log) ? pow(base_log, (x)) : (x))
  179. #else
  180. static double
  181. CheckLog(is_log, base_log, x)
  182.      TBOOLEAN is_log;
  183.      double base_log;
  184.      double x;
  185. {
  186.   if (is_log)
  187.     return(pow(base_log, x));
  188.   else
  189.     return(x);
  190. }
  191. #endif /* sun386 */
  192.  
  193. #ifdef THINK_C_1
  194. double
  195. LogScale(coord, is_log, log_base_log, what, axis)
  196.     double coord;            /* the value */
  197.     TBOOLEAN is_log;            /* is this axis in logscale? */
  198.         double log_base_log;        /* if so, the log of its base */
  199.     char *what;            /* what is the coord for? */
  200.     char *axis;            /* which axis is this for ("x" or "y")? */
  201. {
  202.     if (is_log) {
  203.        if (coord <= 0.0) {
  204.           char errbuf[100];        /* place to write error message */
  205.         (void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
  206.                 what, axis, coord);
  207.           (*term_tbl[term].text)();
  208.           (void) fflush(outfile);
  209.           int_error(errbuf, NO_CARET);
  210.        } else
  211.         return(log(coord)/log_base_log);
  212.     }
  213.     return(coord);
  214. }
  215.  
  216. /* borders of plotting area */
  217. /* computed once on every call to do_plot */
  218. boundary(scaling)
  219.     TBOOLEAN scaling;        /* TRUE if terminal is doing the scaling */
  220. {
  221.     register struct termentry *t = &term_tbl[term];
  222.     /* luecken@udel.edu modifications 
  223.        sizes the plot according to the presence of labels, title,... */
  224.     if (strlen(ylabel) == 0)
  225.         xleft = (t->h_char)*8;
  226.     else
  227.         xleft = (t->h_char)*10;
  228.     xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
  229.     if ((strlen(xlabel) != 0) || timedate)
  230.         if ((*t->text_angle)(1))
  231.             ybot = (t->v_char)*5/2 + 1;
  232.         else
  233.             ybot = (t->v_char)*7/2 + 1;    /* allow space for time at bottom */
  234.     else
  235.         ybot = (t->v_char)*3/2 + 1;
  236.     if ( (strlen(title) != 0) || timedate ||
  237.       ((strlen(ylabel) != 0) && ((*t->text_angle)(1) == FALSE)) )
  238.         ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)*3/2 - 1;
  239.     else
  240.         ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)/2 - 1;
  241.     (void)(*t->text_angle)(0);
  242. }
  243.  
  244.  
  245. double dbl_raise(x,y)
  246. double x;
  247. int y;
  248. {
  249. register int i;
  250. double val;
  251.  
  252.     val = 1.0;
  253.     for (i=0; i < abs(y); i++)
  254.         val *= x;
  255.     if (y < 0 ) return (1.0/val);
  256.     return(val);
  257. }
  258.  
  259.  
  260. double make_tics(tmin,tmax,logscale,base_log)
  261. double tmin,tmax;
  262. TBOOLEAN logscale;
  263. double base_log;
  264. {
  265. register double xr,xnorm,tics,tic,l10;
  266.  
  267.     xr = fabs(tmin-tmax);
  268.     
  269.     l10 = log10(xr);
  270.     if (logscale) {
  271.         tic = dbl_raise(base_log,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  272.         if (tic < 1.0)
  273.             tic = 1.0;
  274.     } else {
  275.         xnorm = pow(10.0,l10-(double)((l10 >= 0.0 ) ? (int)l10 : ((int)l10-1)));
  276.         if (xnorm <= 2)
  277.             tics = 0.2;
  278.         else if (xnorm <= 5)
  279.             tics = 0.5;
  280.         else tics = 1.0;    
  281.         tic = tics * dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  282.     }
  283.     return(tic);
  284. }
  285.  
  286.  
  287. do_plot(plots, pcount, min_x, max_x, min_y, max_y)
  288. struct curve_points *plots;
  289. int pcount;            /* count of plots in linked list */
  290. double min_x, max_x;
  291. double min_y, max_y;
  292. {
  293. register struct termentry *t = &term_tbl[term];
  294. register int curve, xaxis_y, yaxis_x;
  295. register struct curve_points *this_plot;
  296. register double ytic, xtic;
  297. register int xl, yl;
  298.             /* only a Pyramid would have this many registers! */
  299. double xtemp, ytemp;
  300. struct text_label *this_label;
  301. struct arrow_def *this_arrow;
  302. TBOOLEAN scaling;
  303.  
  304.  
  305. /* store these in variables global to this file */
  306. /* otherwise, we have to pass them around a lot */
  307.      x_min = min_x;
  308.      x_max = max_x; 
  309.      y_min = min_y;
  310.      y_max = max_y;
  311.  
  312.     if (polar) {
  313.         /* will possibly change x_min, x_max, y_min, y_max */
  314.         polar_xform(plots,pcount);
  315.     }
  316.  
  317.     if (y_min == VERYLARGE || y_max == -VERYLARGE ||
  318.         x_min == VERYLARGE || x_max == -VERYLARGE)
  319.         int_error("all points undefined!", NO_CARET);
  320.  
  321. /*    Apply the desired viewport offsets. */
  322.      if (y_min < y_max) {
  323.         y_min -= boff;
  324.         y_max += toff;
  325.     } else {
  326.         y_max -= boff;
  327.         y_min += toff;
  328.     }
  329.      if (x_min < x_max) {
  330.         x_min -= loff;
  331.         x_max += roff;
  332.     } else {
  333.         x_max -= loff;
  334.         x_min += roff;
  335.     }
  336.  
  337. /* SETUP RANGES, SCALES AND TIC PLACES */
  338.     if (ytics && yticdef.type == TIC_COMPUTED) {
  339.        ytic = make_tics(y_min,y_max,is_log_y,base_log_y);
  340.     
  341.        if (autoscale_ly) {
  342.           if (y_min < y_max) {
  343.              y_min = ytic * floor(y_min/ytic);       
  344.              y_max = ytic * ceil(y_max/ytic);
  345.           }
  346.           else {            /* reverse axis */
  347.              y_min = ytic * ceil(y_min/ytic);       
  348.              y_max = ytic * floor(y_max/ytic);
  349.           }
  350.        }
  351.     }
  352.  
  353.     if (xtics && xticdef.type == TIC_COMPUTED) {
  354.        xtic = make_tics(x_min,x_max,is_log_x,base_log_x);
  355.        
  356.        if (autoscale_lx) {
  357.           if (x_min < x_max) {
  358.              x_min = xtic * floor(x_min/xtic);    
  359.              x_max = xtic * ceil(x_max/xtic);
  360.           } else {
  361.              x_min = xtic * ceil(x_min/xtic);
  362.              x_max = xtic * floor(x_max/xtic);    
  363.           }
  364.        }
  365.     }
  366.  
  367. /*    This used be x_max == x_min, but that caused an infinite loop once. */
  368.     if (fabs(x_max - x_min) < zero)
  369.         int_error("x_min should not equal x_max!",NO_CARET);
  370.     if (fabs(y_max - y_min) < zero)
  371.         int_error("y_min should not equal y_max!",NO_CARET);
  372.  
  373. /* INITIALIZE TERMINAL */
  374.     if (!term_init) {
  375.         (*t->init)();
  376.         term_init = TRUE;
  377.     }
  378.     screen_ok = FALSE;
  379.     scaling = (*t->scale)(xsize, ysize);
  380.     (*t->graphics)();
  381.  
  382.      /* now compute boundary for plot (xleft, xright, ytop, ybot) */
  383.      boundary(scaling);
  384.  
  385. /* SCALE FACTORS */
  386.     yscale = (ytop - ybot)/(y_max - y_min);
  387.     xscale = (xright - xleft)/(x_max - x_min);
  388.     
  389. /* DRAW AXES */
  390.     (*t->linetype)(-1);    /* axis line type */
  391.     xaxis_y = map_y(0.0);
  392.     yaxis_x = map_x(0.0); 
  393.  
  394.     if (xaxis_y < ybot)
  395.         xaxis_y = ybot;                /* save for impulse plotting */
  396.     else if (xaxis_y >= ytop)
  397.         xaxis_y = ytop ;
  398.     else if (xzeroaxis && !is_log_y) {
  399.         (*t->move)(xleft,xaxis_y);
  400.         (*t->vector)(xright,xaxis_y);
  401.     } else if (is_log_y){
  402.         xaxis_y = ybot;
  403.     }
  404.  
  405.     if (yzeroaxis && !is_log_x && yaxis_x >= xleft && yaxis_x < xright ) {
  406.         (*t->move)(yaxis_x,ybot);
  407.         (*t->vector)(yaxis_x,ytop);
  408.     }
  409.  
  410. /* DRAW TICS */
  411.     (*t->linetype)(-2); /* border linetype */
  412.  
  413.     /* label y axis tics */
  414.      if (ytics) {
  415.         switch (yticdef.type) {
  416.            case TIC_COMPUTED: {
  417.                if (y_min < y_max)
  418.                 draw_ytics(ytic * floor(y_min/ytic),
  419.                         ytic,
  420.                         ytic * ceil(y_max/ytic));
  421.               else
  422.                 draw_ytics(ytic * floor(y_max/ytic),
  423.                         ytic,
  424.                         ytic * ceil(y_min/ytic));
  425.  
  426.               break;
  427.            }
  428.             case TIC_MONTH:{
  429.             draw_month_ytics();
  430.             break;
  431.             }
  432.             case TIC_DAY: {
  433.             draw_day_ytics();
  434.             break;
  435.             }
  436.            case TIC_SERIES: {
  437.               draw_series_ytics(yticdef.def.series.start, 
  438.                             yticdef.def.series.incr, 
  439.                             yticdef.def.series.end);
  440.               break;
  441.            }
  442.            case TIC_USER: {
  443.               draw_set_ytics(yticdef.def.user);
  444.               break;
  445.            }
  446.            default: {
  447.               (*t->text)();
  448.                 (void) fflush(outfile);
  449.               int_error("unknown tic type in yticdef in do_plot", NO_CARET);
  450.               break;        /* NOTREACHED */
  451.            }
  452.         }
  453.     }
  454.  
  455.     /* label x axis tics */
  456.      if (xtics) {
  457.         switch (xticdef.type) {
  458.            case TIC_COMPUTED: {
  459.                if (x_min < x_max)
  460.                 draw_xtics(xtic * floor(x_min/xtic),
  461.                         xtic,
  462.                         xtic * ceil(x_max/xtic));
  463.               else
  464.                 draw_xtics(xtic * floor(x_max/xtic),
  465.                         xtic,
  466.                         xtic * ceil(x_min/xtic));
  467.  
  468.               break;
  469.            }
  470.             case TIC_MONTH: {
  471.             draw_month_xtics();
  472.             break;
  473.             }
  474.             case TIC_DAY : {
  475.             draw_day_xtics();
  476.             break;
  477.             }
  478.            case TIC_SERIES: {
  479.               draw_series_xtics(xticdef.def.series.start, 
  480.                             xticdef.def.series.incr, 
  481.                             xticdef.def.series.end);
  482.               break;
  483.            }
  484.            case TIC_USER: {
  485.               draw_set_xtics(xticdef.def.user);
  486.               break;
  487.            }
  488.            default: {
  489.               (*t->text)();
  490.               (void) fflush(outfile);
  491.               int_error("unknown tic type in xticdef in do_plot", NO_CARET);
  492.               break;        /* NOTREACHED */
  493.            }
  494.         }
  495.     }
  496.  
  497. /* DRAW PLOT BORDER */
  498.     (*t->linetype)(-2); /* border linetype */
  499.     if (draw_border) {
  500.         (*t->move)(xleft,ybot);
  501.         (*t->vector)(xright,ybot);
  502.         (*t->vector)(xright,ytop);
  503.         (*t->vector)(xleft,ytop);
  504.         (*t->vector)(xleft,ybot);
  505.     }
  506.  
  507. /* PLACE YLABEL */
  508.     if (strlen(ylabel) > 0) {
  509.         int x, y;
  510.  
  511.         x = ylabel_xoffset * t->h_char;
  512.         y = ylabel_yoffset * t->v_char;
  513.         if ((*t->text_angle)(1)) {
  514.             if ((*t->justify_text)(CENTRE)) {
  515.                 (*t->put_text)(x+(t->v_char),
  516.                          y+(ytop+ybot)/2, ylabel);
  517.             }
  518.             else {
  519.                 (*t->put_text)(x+(t->v_char),
  520.                            y+(ytop+ybot)/2-(t->h_char)*strlen(ylabel)/2, 
  521.                          ylabel);
  522.             }
  523.         }
  524.         else {
  525.             (void)(*t->justify_text)(LEFT);
  526.             (*t->put_text)(x,y+ytop+(t->v_char), ylabel);
  527.         }
  528.         (void)(*t->text_angle)(0);
  529.     }
  530.  
  531. /* PLACE XLABEL */
  532.     if (strlen(xlabel) > 0) {
  533.         int x, y;
  534.  
  535.         x = xlabel_xoffset * t->h_char;
  536.         y = xlabel_yoffset * t->v_char;
  537.  
  538.             if ((*t->justify_text)(CENTRE)) 
  539.             (*t->put_text)(x+(xleft+xright)/2,
  540.                        y+ybot-2*(t->v_char), xlabel);
  541.             else
  542.             (*t->put_text)(x+(xleft+xright)/2 - strlen(xlabel)*(t->h_char)/2,
  543.                            y+ybot-2*(t->v_char), xlabel);
  544.     }
  545.  
  546. /* PLACE TITLE */
  547.     if (strlen(title) > 0) {
  548.         int x, y;
  549.  
  550.         x = title_xoffset * t->h_char;
  551.         y = title_yoffset * t->v_char;
  552.  
  553.             if ((*t->justify_text)(CENTRE))
  554.             (*t->put_text)(x+(xleft+xright)/2,
  555.                        y+ytop+(t->v_char), title);
  556.             else
  557.             (*t->put_text)(x+(xleft+xright)/2 - strlen(title)*(t->h_char)/2,
  558.                        y+ytop+(t->v_char), title);
  559.     }
  560.  
  561.  
  562. /* PLACE TIMEDATE */
  563.     if (timedate) {
  564.         int x, y;
  565.  
  566.         x = time_xoffset * t->h_char;
  567.         y = time_yoffset * t->v_char;
  568.         dated = time( (time_t *) 0);
  569.         tdate = ctime( &dated);
  570.         tdate[24]='\0';
  571.         (void)(*t->justify_text)(LEFT);
  572.         if ((*t->text_angle)(1)) {
  573.             (void)(*t->text_angle)(0);
  574.             (*t->put_text)(x, y+ytop+(t->v_char), tdate);
  575.         }
  576.         else {
  577.             (void)(*t->text_angle)(0);
  578.             (*t->put_text)(x,
  579.                          y+ybot-3*(t->v_char), tdate);
  580.         }
  581.     }
  582.  
  583. /* PLACE LABELS */
  584.     for (this_label = first_label; this_label!=NULL;
  585.             this_label=this_label->next ) {
  586.          xtemp = LogScale(this_label->x, is_log_x, log_base_log_x, "label", "x");
  587.          ytemp = LogScale(this_label->y, is_log_y, log_base_log_y, "label", "y");
  588.         if ((*t->justify_text)(this_label->pos)) {
  589.             (*t->put_text)(map_x(xtemp),map_y(ytemp),this_label->text);
  590.         }
  591.         else {
  592.             switch(this_label->pos) {
  593.                 case  LEFT:
  594.                     (*t->put_text)(map_x(xtemp),map_y(ytemp),
  595.                         this_label->text);
  596.                     break;
  597.                 case CENTRE:
  598.                     (*t->put_text)(map_x(xtemp)-
  599.                         (t->h_char)*strlen(this_label->text)/2,
  600.                         map_y(ytemp), this_label->text);
  601.                     break;
  602.                 case RIGHT:
  603.                     (*t->put_text)(map_x(xtemp)-
  604.                         (t->h_char)*strlen(this_label->text),
  605.                         map_y(ytemp), this_label->text);
  606.                     break;
  607.             }
  608.          }
  609.      }
  610.  
  611. /* PLACE ARROWS */
  612.     (*t->linetype)(0);    /* arrow line type */
  613.     for (this_arrow = first_arrow; this_arrow!=NULL;
  614.         this_arrow = this_arrow->next ) {
  615.        int sx = map_x(LogScale(this_arrow->sx, is_log_x, log_base_log_x, "arrow", "x"));
  616.        int sy = map_y(LogScale(this_arrow->sy, is_log_y, log_base_log_y, "arrow", "y"));
  617.        int ex = map_x(LogScale(this_arrow->ex, is_log_x, log_base_log_x, "arrow", "x"));
  618.        int ey = map_y(LogScale(this_arrow->ey, is_log_y, log_base_log_y, "arrow", "y"));
  619.        
  620.        (*t->arrow)(sx, sy, ex, ey, this_arrow->head);
  621.     }
  622.  
  623.  
  624. /* DRAW CURVES */
  625.     if (key == -1) {
  626.         xl = xright  - (t->h_tic) - (t->h_char)*5;
  627.         yl = ytop - (t->v_tic) - (t->v_char);
  628.     }
  629.     if (key == 1) {
  630.         xl = map_x( LogScale(key_x, is_log_x, log_base_log_x, "key", "x") );
  631.         yl = map_y( LogScale(key_y, is_log_y, log_base_log_y, "key", "y") );
  632.     }
  633.  
  634.     this_plot = plots;
  635.     for (curve = 0; curve < pcount; this_plot = this_plot->next_cp, curve++) {
  636.         int oldkey = key;
  637.  
  638.         (*t->linetype)(this_plot->line_type);
  639.  
  640.         if (this_plot->title && !*this_plot->title) {
  641.             key = 0;
  642.         } else {
  643.         if (key != 0 && this_plot->title) {
  644.             if ((*t->justify_text)(RIGHT)) {
  645.                 (*t->put_text)(xl,
  646.                     yl,this_plot->title);
  647.             }
  648.             else {
  649.                 if (inrange(xl-(t->h_char)*strlen(this_plot->title), 
  650.                          xleft, xright))
  651.                  (*t->put_text)(xl-(t->h_char)*strlen(this_plot->title),
  652.                              yl,this_plot->title);
  653.             }
  654.         }
  655.         }
  656.  
  657.         switch(this_plot->plot_style) {
  658.             case IMPULSES: {
  659.                if (key != 0 && this_plot->title) {
  660.                   (*t->move)(xl+(t->h_char),yl);
  661.                   (*t->vector)(xl+4*(t->h_char),yl);
  662.                }
  663.                plot_impulses(this_plot, yaxis_x, xaxis_y);
  664.                break;
  665.             }
  666.             case LINES: {
  667.                if (key != 0 && this_plot->title) {
  668.                   (*t->move)(xl+(int)(t->h_char),yl);
  669.                   (*t->vector)(xl+(int)(4*(t->h_char)),yl);
  670.                }
  671.                plot_lines(this_plot);
  672.                break;
  673.             }
  674. /* JG */        case STEPS: {
  675.                if (key != 0 && this_plot->title) {
  676.                   (*t->move)(xl+(int)(t->h_char),yl);
  677.                   (*t->vector)(xl+(int)(4*(t->h_char)),yl);
  678.                }
  679.                plot_steps(this_plot);
  680.                break;
  681.             }
  682.             case POINTSTYLE: {
  683.                if (key != 0 && this_plot->title) {
  684.                   (*t->point)(xl+2*(t->h_char),yl,
  685.                             this_plot->point_type);
  686.                }
  687.                plot_points(this_plot);
  688.                break;
  689.             }
  690.             case LINESPOINTS: {
  691.                /* put lines */
  692.                if (key != 0 && this_plot->title) {
  693.                   (*t->move)(xl+(t->h_char),yl);
  694.                   (*t->vector)(xl+4*(t->h_char),yl);
  695.                }
  696.                plot_lines(this_plot);
  697.  
  698.                /* put points */
  699.                if (key != 0 && this_plot->title) {
  700.                   (*t->point)(xl+2*(t->h_char),yl,
  701.                             this_plot->point_type);
  702.                }
  703.                plot_points(this_plot);
  704.                break;
  705.             }
  706.             case DOTS: {
  707.                if (key != 0 && this_plot->title) {
  708.                   (*t->point)(xl+2*(t->h_char),yl, -1);
  709.                }
  710.                plot_dots(this_plot);
  711.                break;
  712.             }
  713.             case ERRORBARS: {
  714.                if (key != 0 && this_plot->title) {
  715.                   (*t->point)(xl+2*(t->h_char),yl,
  716.                             this_plot->point_type);
  717.                }
  718.                plot_points(this_plot);
  719.  
  720.                /* for functions, just like POINTSTYLE */
  721.                if (this_plot->plot_type == DATA) {
  722.                   if (key != 0 && this_plot->title) {
  723.                      (*t->move)(xl+(t->h_char),yl);
  724.                      (*t->vector)(xl+4*(t->h_char),yl);
  725.                      (*t->move)(xl+(t->h_char),yl+ERRORBARTIC);
  726.                      (*t->vector)(xl+(t->h_char),yl-ERRORBARTIC);
  727.                      (*t->move)(xl+4*(t->h_char),yl+ERRORBARTIC);
  728.                      (*t->vector)(xl+4*(t->h_char),yl-ERRORBARTIC);
  729.                   }
  730.                   plot_bars(this_plot);
  731.                }
  732.                break;
  733.             }
  734.             case BOXERROR: {
  735.                if (this_plot->plot_type == DATA) {
  736.                   if (key != 0 && this_plot->title) {
  737.                      (*t->move)(xl+(t->h_char),yl+ERRORBARTIC);
  738.                      (*t->vector)(xl+(t->h_char),yl-ERRORBARTIC);
  739.                      (*t->move)(xl+4*(t->h_char),yl+ERRORBARTIC);
  740.                      (*t->vector)(xl+4*(t->h_char),yl-ERRORBARTIC);
  741.                   }
  742.                   plot_bars(this_plot);
  743.                }
  744.             }
  745.             /* no break */
  746.             case BOXES: {
  747.                if (key != 0 && this_plot->title) {
  748.                   (*t->move)(xl+(t->h_char),yl);
  749.                   (*t->vector)(xl+4*(t->h_char),yl);
  750.                }
  751.                plot_boxes(this_plot,xaxis_y);
  752.                break;
  753.             }
  754.  
  755.         }
  756.         if (key && this_plot->title) {
  757.             yl = yl - (t->v_char);
  758.         }
  759.         key = oldkey;
  760.     }
  761.     (*t->text)();
  762.     (void) fflush(outfile);
  763. }
  764.  
  765. /* plot_impulses:
  766.  * Plot the curves in IMPULSES style
  767.  */
  768. void
  769. plot_impulses(plot, yaxis_x, xaxis_y)
  770.     struct curve_points *plot;
  771.     int yaxis_x, xaxis_y;
  772. {
  773.     int i;
  774.     int x,y;
  775.     struct termentry *t = &term_tbl[term];
  776.  
  777.     for (i = 0; i < plot->p_count; i++) {
  778.        switch (plot->points[i].type) {
  779.           case INRANGE: {
  780.              x = map_x(plot->points[i].x);
  781.              y = map_y(plot->points[i].y);
  782.              break;
  783.           }
  784.           case OUTRANGE: {
  785.              if (!inrange(plot->points[i].x, x_min,x_max))
  786.                continue;
  787.              x = map_x(plot->points[i].x);
  788.              if ((y_min < y_max 
  789.                  && plot->points[i].y < y_min)
  790.                 || (y_max < y_min 
  791.                     && plot->points[i].y > y_min))
  792.                y = map_y(y_min);
  793.              if ((y_min < y_max 
  794.                  && plot->points[i].y > y_max)
  795.                 || (y_max<y_min 
  796.                     && plot->points[i].y < y_max))
  797.                y = map_y(y_max);
  798.              break;
  799.           }
  800.           default:        /* just a safety */
  801.           case UNDEFINED: {
  802.              continue;
  803.           }
  804.        }
  805.                     
  806.        if (polar)
  807.           (*t->move)(yaxis_x,xaxis_y);
  808.        else
  809.           (*t->move)(x,xaxis_y);
  810.        (*t->vector)(x,y);
  811.     }
  812.  
  813. }
  814.  
  815. /* plot_lines:
  816.  * Plot the curves in LINES style
  817.  */
  818. void
  819. plot_lines(plot)
  820.     struct curve_points *plot;
  821. {
  822.     int i;                /* point index */
  823.     int x,y;                /* point in terminal coordinates */
  824.     struct termentry *t = &term_tbl[term];
  825.     enum coord_type prev = UNDEFINED; /* type of previous point */
  826.     double ex, ey;            /* an edge point */
  827.     double lx[2], ly[2];        /* two edge points */
  828.  
  829.     for (i = 0; i < plot->p_count; i++) {
  830.        switch (plot->points[i].type) {
  831.           case INRANGE: {
  832.              x = map_x(plot->points[i].x);
  833.              y = map_y(plot->points[i].y);
  834.  
  835.              if (prev == INRANGE) {
  836.                 (*t->vector)(x,y);
  837.              } else if (prev == OUTRANGE) {
  838.                 /* from outrange to inrange */
  839.                 if (!clip_lines1) {
  840.                     (*t->move)(x,y);
  841.                 } else {
  842.                     edge_intersect(plot->points, i, &ex, &ey);
  843.                     (*t->move)(map_x(ex), map_y(ey));
  844.                     (*t->vector)(x,y);
  845.                 }
  846.              } else {        /* prev == UNDEFINED */
  847.                 (*t->move)(x,y);
  848.                 (*t->vector)(x,y);
  849.              }
  850.                     
  851.              break;
  852.           }
  853.           case OUTRANGE: {
  854.              if (prev == INRANGE) {
  855.                 /* from inrange to outrange */
  856.                 if (clip_lines1) {
  857.                     edge_intersect(plot->points, i, &ex, &ey);
  858.                     (*t->vector)(map_x(ex), map_y(ey));
  859.                 }
  860.              } else if (prev == OUTRANGE) {
  861.                 /* from outrange to outrange */
  862.                 if (clip_lines2) {
  863.                     if (two_edge_intersect(plot->points, i, lx, ly)) {
  864.                        (*t->move)(map_x(lx[0]), map_y(ly[0]));
  865.                        (*t->vector)(map_x(lx[1]), map_y(ly[1]));
  866.                     }
  867.                 }
  868.              }
  869.              break;
  870.           }
  871.           default:        /* just a safety */
  872.           case UNDEFINED: {
  873.              break;
  874.           }
  875.        }
  876.        prev = plot->points[i].type;
  877.     }
  878. }
  879.  
  880. /* XXX - JG  */
  881. /* plot_steps:                
  882.  * Plot the curves in STEPS style
  883.  */
  884. void
  885. plot_steps(plot)
  886. struct curve_points *plot;
  887. {
  888.     int i;                /* point index */
  889.     int x,y;                /* point in terminal coordinates */
  890.     struct termentry *t = &term_tbl[term];
  891.     enum coord_type prev = UNDEFINED;    /* type of previous point */
  892.     double ex, ey;            /* an edge point */
  893.     double lx[2], ly[2];        /* two edge points */
  894.     int xprev, yprev;            /* previous point coordinates */
  895.  
  896.     for (i = 0; i < plot->p_count; i++) {
  897.        switch (plot->points[i].type) {
  898.           case INRANGE: {
  899.              x = map_x(plot->points[i].x);
  900.              y = map_y(plot->points[i].y);
  901.  
  902.              if (prev == INRANGE) {
  903.                 (*t->vector)(x,yprev);
  904.                 (*t->vector)(x,y);
  905.              } else if (prev == OUTRANGE) {
  906.                 /* from outrange to inrange */
  907.                 if (!clip_lines1) {
  908.                     (*t->move)(x,y);
  909.                 } else {        /* find edge intersection */
  910.                     edge_intersect_steps(plot->points, i, &ex, &ey);
  911.                     (*t->move)(map_x(ex), map_y(ey));
  912.                     (*t->vector)(x,map_y(ey));
  913.                     (*t->vector)(x,y);
  914.                 }
  915.              } else {        /* prev == UNDEFINED */
  916.                 (*t->move)(x,y);
  917.                 (*t->vector)(x,y);
  918.              }
  919.              break;
  920.           }
  921.           case OUTRANGE: {
  922.              if (prev == INRANGE) {
  923.                 /* from inrange to outrange */
  924.                 if (clip_lines1) {
  925.                     edge_intersect_steps(plot->points, i, &ex, &ey);
  926.                     (*t->vector)(map_x(ex), yprev);
  927.                     (*t->vector)(map_x(ex), map_y(ey));
  928.                 }
  929.              } else if (prev == OUTRANGE) {
  930.                 /* from outrange to outrange */
  931.                 if (clip_lines2) {
  932.                     if (two_edge_intersect_steps(plot->points, i, lx, ly)) {
  933.                        (*t->move)(map_x(lx[0]), map_y(ly[0]));
  934.                        (*t->vector)(map_x(lx[1]), map_y(ly[0]));
  935.                        (*t->vector)(map_x(lx[1]), map_y(ly[1]));
  936.                     }
  937.                 }
  938.              }
  939.              break;
  940.           }
  941.           default:        /* just a safety */
  942.           case UNDEFINED: {
  943.              break;
  944.           }
  945.        }
  946.        prev  = plot->points[i].type;
  947.        xprev = x;
  948.        yprev = y;
  949.     }
  950. }
  951.  
  952. /* plot_bars:
  953.  * Plot the curves in ERRORBARS style
  954.  *  we just plot the bars; the points are plotted in plot_points
  955.  */
  956. void
  957. plot_bars(plot)
  958.     struct curve_points *plot;
  959. {
  960.     int i;                /* point index */
  961.     struct termentry *t = &term_tbl[term];
  962.     double x;                /* position of the bar */
  963.     double ylow, yhigh;        /* the ends of the bars */
  964.     unsigned int xM, ylowM, yhighM; /* the mapped version of above */
  965.     TBOOLEAN low_inrange, high_inrange;
  966.     int tic = ERRORBARTIC;
  967.     
  968.     for (i = 0; i < plot->p_count; i++) {
  969.        /* undefined points don't count */
  970.        if (plot->points[i].type == UNDEFINED)
  971.         continue;
  972.  
  973.        /* check to see if in xrange */
  974.        x = plot->points[i].x;
  975.        if (! inrange(x, x_min, x_max))
  976.         continue;
  977.        xM = map_x(x);
  978.  
  979.        /* find low and high points of bar, and check yrange */
  980.        yhigh = plot->points[i].yhigh;
  981.        ylow = plot->points[i].ylow;
  982.  
  983.        high_inrange = inrange(yhigh, y_min,y_max);
  984.        low_inrange = inrange(ylow, y_min,y_max);
  985.  
  986.        /* compute the plot position of yhigh */
  987.        if (high_inrange)
  988.         yhighM = map_y(yhigh);
  989.        else if (samesign(yhigh-y_max, y_max-y_min))
  990.         yhighM = map_y(y_max);
  991.        else
  992.         yhighM = map_y(y_min);
  993.        
  994.        /* compute the plot position of ylow */
  995.        if (low_inrange)
  996.         ylowM = map_y(ylow);
  997.        else if (samesign(ylow-y_max, y_max-y_min))
  998.         ylowM = map_y(y_max);
  999.        else
  1000.         ylowM = map_y(y_min);
  1001.  
  1002.        if (!high_inrange && !low_inrange && ylowM == yhighM)
  1003.         /* both out of range on the same side */
  1004.           continue;
  1005.  
  1006.        /* by here everything has been mapped */
  1007.        (*t->move)(xM, ylowM);
  1008.        (*t->vector)(xM, yhighM); /* draw the main bar */
  1009.        (*t->move)(xM-tic, ylowM); /* draw the bottom tic */
  1010.        (*t->vector)(xM+tic, ylowM);
  1011.        (*t->move)(xM-tic, yhighM); /* draw the top tic */
  1012.        (*t->vector)(xM+tic, yhighM);
  1013.     }
  1014. }
  1015.  
  1016. /* plot_boxes:
  1017.  * Plot the curves in BOXES style
  1018.  */
  1019. void
  1020. plot_boxes(plot,xaxis_y)
  1021.     struct curve_points *plot;
  1022.     int xaxis_y;
  1023. {
  1024.     int i;                /* point index */
  1025.     int xl,xr,yt;            /* point in terminal coordinates */
  1026.     double dxl,dxr,dyt;
  1027.     struct termentry *t = &term_tbl[term];
  1028.     enum coord_type prev = UNDEFINED; /* type of previous point */
  1029.  
  1030.     for (i = 0; i < plot->p_count; i++) {
  1031.        switch (plot->points[i].type) {
  1032.           case OUTRANGE:
  1033.           case INRANGE: {
  1034.             if (plot->points[i].z<0.0) {
  1035.                if (boxwidth<0.0) {
  1036.                     /* calculate width */
  1037.                     if (prev!=UNDEFINED)
  1038.                         dxl = (plot->points[i-1].x - plot->points[i].x)/2.0;
  1039.                     else
  1040.                         dxl = 0.0;
  1041.                     if (i < plot->p_count-1) {
  1042.                         if (plot->points[i+1].type!=UNDEFINED)
  1043.                             dxr = (plot->points[i+1].x - plot->points[i].x)/2.0;
  1044.                         else
  1045.                             dxr = -dxl;
  1046.                     }
  1047.                     else {
  1048.                         dxr = -dxl;
  1049.                     }
  1050.                     if (prev==UNDEFINED)
  1051.                         dxl = -dxr;
  1052.                 }
  1053.                 else {
  1054.                     dxr = boxwidth/2.0;
  1055.                     dxl = -dxr;
  1056.                 }
  1057.             }
  1058.             else {
  1059.                 dxr = plot->points[i].z/2.0;
  1060.                 dxl = -dxr;
  1061.             }
  1062.  
  1063.             dxl= plot->points[i].x+dxl;
  1064.             dxr= plot->points[i].x+dxr;
  1065.             dyt= plot->points[i].y;
  1066.  
  1067.             /* clip to border */
  1068.             if ((y_min < y_max  && dyt < y_min)
  1069.                 || (y_max < y_min  && dyt > y_min))
  1070.                dyt = y_min;
  1071.             if ((y_min < y_max  && dyt > y_max)
  1072.                 || (y_max<y_min  && dyt < y_max))
  1073.                dyt = y_max;
  1074.             if ((x_min < x_max  && dxr < x_min)
  1075.                 || (x_max < x_min  && dxr > x_min))
  1076.                dxr = x_min;
  1077.             if ((x_min < x_max  && dxr > x_max)
  1078.                 || (x_max<x_min  && dxr < x_max))
  1079.                dxr = x_max;
  1080.             if ((x_min < x_max  && dxl < x_min)
  1081.                 || (x_max < x_min  && dxl > x_min))
  1082.                dxl = x_min;
  1083.             if ((x_min < x_max  && dxl > x_max)
  1084.                 || (x_max<x_min  && dxl < x_max))
  1085.                dxl = x_max;
  1086.  
  1087.             xl= map_x(dxl);
  1088.             xr= map_x(dxr);
  1089.             yt = map_y(dyt);
  1090.  
  1091.             (*t->move)(xl,xaxis_y);
  1092.             (*t->vector)(xl,yt);
  1093.             (*t->vector)(xr,yt);
  1094.             (*t->vector)(xr,xaxis_y);
  1095.             (*t->vector)(xl,xaxis_y);
  1096.             break;
  1097.           }
  1098.           default:        /* just a safety */
  1099.           case UNDEFINED: {
  1100.              break;
  1101.           }
  1102.        }
  1103.        prev = plot->points[i].type;
  1104.     }
  1105. }
  1106.  
  1107. /* plot_points:
  1108.  * Plot the curves in POINTSTYLE style
  1109.  */
  1110. void
  1111. plot_points(plot)
  1112.     struct curve_points *plot;
  1113. {
  1114.     int i;
  1115.     int x,y;
  1116.     struct termentry *t = &term_tbl[term];
  1117.  
  1118.     for (i = 0; i < plot->p_count; i++) {
  1119.        if (plot->points[i].type == INRANGE) {
  1120.           x = map_x(plot->points[i].x);
  1121.           y = map_y(plot->points[i].y);
  1122.           /* do clipping if necessary */
  1123.           if (!clip_points ||
  1124.              (   x >= xleft + t->h_tic  && y >= ybot + t->v_tic 
  1125.               && x <= xright - t->h_tic && y <= ytop - t->v_tic))
  1126.             (*t->point)(x,y, plot->point_type);
  1127.        }
  1128.     }
  1129. }
  1130.  
  1131. /* plot_dots:
  1132.  * Plot the curves in DOTS style
  1133.  */
  1134. void
  1135. plot_dots(plot)
  1136.     struct curve_points *plot;
  1137. {
  1138.     int i;
  1139.     int x,y;
  1140.     struct termentry *t = &term_tbl[term];
  1141.  
  1142.     for (i = 0; i < plot->p_count; i++) {
  1143.        if (plot->points[i].type == INRANGE) {
  1144.           x = map_x(plot->points[i].x);
  1145.           y = map_y(plot->points[i].y);
  1146.           /* point type -1 is a dot */
  1147.           (*t->point)(x,y, -1);
  1148.        }
  1149.     }
  1150. }
  1151. #endif /* THINK_C_1 */
  1152.  
  1153. #ifdef THINK_C_2
  1154.  
  1155.  
  1156. /* single edge intersection algorithm */
  1157. /* Given two points, one inside and one outside the plot, return
  1158.  * the point where an edge of the plot intersects the line segment defined 
  1159.  * by the two points.
  1160.  */
  1161. void
  1162. edge_intersect(points, i, ex, ey)
  1163.     struct coordinate GPHUGE *points; /* the points array */
  1164.     int i;                /* line segment from point i-1 to point i */
  1165.     double *ex, *ey;        /* the point where it crosses an edge */
  1166. {
  1167.     /* global x_min, x_max, y_min, x_max */
  1168.     double ax = points[i-1].x;
  1169.     double ay = points[i-1].y;
  1170.     double bx = points[i].x;
  1171.     double by = points[i].y;
  1172.     double x, y;            /* possible intersection point */
  1173.  
  1174.     if (by == ay) {
  1175.        /* horizontal line */
  1176.        /* assume inrange(by, y_min, y_max) */
  1177.        *ey = by;        /* == ay */
  1178.  
  1179.        if (inrange(x_max, ax, bx))
  1180.         *ex = x_max;
  1181.        else if (inrange(x_min, ax, bx))
  1182.         *ex = x_min;
  1183.        else {
  1184.         (*term_tbl[term].text)();
  1185.         (void) fflush(outfile);
  1186.         int_error("error in edge_intersect", NO_CARET);
  1187.        }
  1188.        return;
  1189.     } else if (bx == ax) {
  1190.        /* vertical line */
  1191.        /* assume inrange(bx, x_min, x_max) */
  1192.        *ex = bx;        /* == ax */
  1193.  
  1194.        if (inrange(y_max, ay, by))
  1195.         *ey = y_max;
  1196.        else if (inrange(y_min, ay, by))
  1197.         *ey = y_min;
  1198.        else {
  1199.         (*term_tbl[term].text)();
  1200.         (void) fflush(outfile);
  1201.         int_error("error in edge_intersect", NO_CARET);
  1202.        }
  1203.        return;
  1204.     }
  1205.  
  1206.     /* slanted line of some kind */
  1207.  
  1208.     /* does it intersect y_min edge */
  1209.     if (inrange(y_min, ay, by) && y_min != ay && y_min != by) {
  1210.        x = ax + (y_min-ay) * ((bx-ax) / (by-ay));
  1211.        if (inrange(x, x_min, x_max)) {
  1212.           *ex = x;
  1213.           *ey = y_min;
  1214.           return;            /* yes */
  1215.        }
  1216.     }
  1217.     
  1218.     /* does it intersect y_max edge */
  1219.     if (inrange(y_max, ay, by) && y_max != ay && y_max != by) {
  1220.        x = ax + (y_max-ay) * ((bx-ax) / (by-ay));
  1221.        if (inrange(x, x_min, x_max)) {
  1222.           *ex = x;
  1223.           *ey = y_max;
  1224.           return;            /* yes */
  1225.        }
  1226.     }
  1227.  
  1228.     /* does it intersect x_min edge */
  1229.     if (inrange(x_min, ax, bx) && x_min != ax && x_min != bx) {
  1230.        y = ay + (x_min-ax) * ((by-ay) / (bx-ax));
  1231.        if (inrange(y, y_min, y_max)) {
  1232.           *ex = x_min;
  1233.           *ey = y;
  1234.           return;
  1235.        }
  1236.     }
  1237.  
  1238.     /* does it intersect x_max edge */
  1239.     if (inrange(x_max, ax, bx) && x_max != ax && x_max != bx) {
  1240.        y = ay + (x_max-ax) * ((by-ay) / (bx-ax));
  1241.        if (inrange(y, y_min, y_max)) {
  1242.           *ex = x_max;
  1243.           *ey = y;
  1244.           return;
  1245.        }
  1246.     }
  1247.  
  1248.     /* It is possible for one or two of the [ab][xy] values to be -VERYLARGE.
  1249.     * If ax=bx=-VERYLARGE or ay=by=-VERYLARGE we have already returned 
  1250.     * FALSE above. Otherwise we fall through all the tests above. 
  1251.     * If two are -VERYLARGE, it is ax=ay=-VERYLARGE or bx=by=-VERYLARGE 
  1252.     * since either a or b must be INRANGE. 
  1253.     * Note that for ax=ay=-VERYLARGE or bx=by=-VERYLARGE we can do nothing.
  1254.     * Handle them carefully here. As yet we have no way for them to be 
  1255.     * +VERYLARGE.
  1256.     */
  1257.     if (ax == -VERYLARGE) {
  1258.        if (ay != -VERYLARGE) {
  1259.           *ex = min(x_min, x_max);
  1260.           *ey = by;
  1261.           return;
  1262.        }
  1263.     } else if (bx == -VERYLARGE) {
  1264.        if (by != -VERYLARGE) {
  1265.           *ex = min(x_min, x_max);
  1266.           *ey = ay;
  1267.           return;
  1268.        }
  1269.     } else if (ay == -VERYLARGE) {
  1270.        /* note we know ax != -VERYLARGE */
  1271.        *ex = bx;
  1272.        *ey = min(y_min, y_max);
  1273.        return;
  1274.     } else if (by == -VERYLARGE) {
  1275.        /* note we know bx != -VERYLARGE */
  1276.        *ex = ax;
  1277.        *ey = min(y_min, y_max);
  1278.        return;
  1279.     }
  1280.  
  1281.     /* If we reach here, then either one point is (-VERYLARGE,-VERYLARGE), 
  1282.     * or the inrange point is on the edge, and
  1283.      * the line segment from the outrange point does not cross any 
  1284.     * other edges to get there. In either case, we return the inrange 
  1285.     * point as the 'edge' intersection point. This will basically draw
  1286.     * line.
  1287.     */
  1288.     if (points[i].type == INRANGE) {
  1289.        *ex = bx; 
  1290.        *ey = by;
  1291.     } else {
  1292.        *ex = ax; 
  1293.        *ey = ay;
  1294.     }
  1295.     return;
  1296. }
  1297.  
  1298. /* XXX - JG  */
  1299. /* single edge intersection algorithm for "steps" curves */
  1300. /* 
  1301.  * Given two points, one inside and one outside the plot, return
  1302.  * the point where an edge of the plot intersects the line segments
  1303.  * forming the step between the two points. 
  1304.  *
  1305.  * Recall that if P1 = (x1,y1) and P2 = (x2,y2), the step from  
  1306.  * P1 to P2 is drawn as two line segments: (x1,y1)->(x2,y1) and 
  1307.  * (x2,y1)->(x2,y2). 
  1308.  */
  1309. void
  1310. edge_intersect_steps(points, i, ex, ey)
  1311.     struct coordinate *points; /* the points array */
  1312.     int i;                /* line segment from point i-1 to point i */
  1313.     double *ex, *ey;        /* the point where it crosses an edge */
  1314. {
  1315.     /* global x_min, x_max, y_min, x_max */
  1316.     double ax = points[i-1].x;
  1317.     double ay = points[i-1].y;
  1318.     double bx = points[i].x;
  1319.     double by = points[i].y;
  1320.  
  1321.     if (points[i].type == INRANGE) {    /* from OUTRANGE to INRANG */
  1322.         if (inrange(ay,y_min,y_max)) {
  1323.         *ey = ay;
  1324.         if (ax > x_max)
  1325.             *ex = x_max;
  1326.         else            /* x < x_min */
  1327.             *ex = x_min;
  1328.         } else {
  1329.             *ex = bx;
  1330.         if (ay > y_max)     
  1331.             *ey = y_max;
  1332.         else            /* y < y_min */
  1333.             *ey = y_min;
  1334.         }
  1335.     } else {                /* from INRANGE to OUTRANGE */
  1336.         if (inrange(bx,x_min,x_max)) {
  1337.         *ex = bx;
  1338.         if (by > y_max)
  1339.             *ey = y_max;
  1340.         else            /* y < y_min */
  1341.             *ey = y_min;
  1342.         } else {
  1343.             *ey = ay;
  1344.         if (bx > x_max)     
  1345.             *ex = x_max;
  1346.         else            /* x < x_min */
  1347.             *ex = x_min;
  1348.         }
  1349.     }
  1350.     return;
  1351. }
  1352.  
  1353. /* XXX - JG  */
  1354. /* double edge intersection algorithm for "steps" plot */
  1355. /* Given two points, both outside the plot, return the points where an 
  1356.  * edge of the plot intersects the line segments forming a step 
  1357.  * by the two points. There may be zero, one, two, or an infinite number
  1358.  * of intersection points. (One means an intersection at a corner, infinite
  1359.  * means overlaying the edge itself). We return FALSE when there is nothing
  1360.  * to draw (zero intersections), and TRUE when there is something to 
  1361.  * draw (the one-point case is a degenerate of the two-point case and we do 
  1362.  * not distinguish it - we draw it anyway).
  1363.  *
  1364.  * Recall that if P1 = (x1,y1) and P2 = (x2,y2), the step from  
  1365.  * P1 to P2 is drawn as two line segments: (x1,y1)->(x2,y1) and 
  1366.  * (x2,y1)->(x2,y2). 
  1367.  */
  1368. TBOOLEAN                /* any intersection? */
  1369. two_edge_intersect_steps(points, i, lx, ly)
  1370.     struct coordinate *points; /* the points array */
  1371.     int i;                /* line segment from point i-1 to point i */
  1372.     double *lx, *ly;        /* lx[2], ly[2]: points where it crosses edges */
  1373. {
  1374.     /* global x_min, x_max, y_min, x_max */
  1375.     double ax = points[i-1].x;
  1376.     double ay = points[i-1].y;
  1377.     double bx = points[i].x;
  1378.     double by = points[i].y;
  1379.  
  1380.     if ( max(ax,bx) < x_min || min(ax,bx) > x_max || 
  1381.          max(ay,by) < y_min || min(ay,by) > y_max ||
  1382.          ( (ay  > y_max || ay < y_min)            &&
  1383.            (bx  > x_max || bx < x_min)  ) ) {
  1384.     return(FALSE);                
  1385.     } else if (inrange(ay,y_min,y_max) && inrange(bx,x_min,x_max)) {    /* corner of step inside plotspace */
  1386.         *ly++ = ay;
  1387.     if (ax < x_min) 
  1388.         *lx++ = x_min;
  1389.     else 
  1390.         *lx++ = x_max;
  1391.  
  1392.     *lx++ = bx;
  1393.     if (by < x_min) 
  1394.         *ly++ = y_min;
  1395.     else 
  1396.         *ly++ = y_max;
  1397.  
  1398.     return(TRUE);
  1399.     } else if (inrange(ay,y_min,y_max)) {    /* cross plotspace in x-direction */
  1400.     *lx++ = x_min;
  1401.     *ly++ = ay;
  1402.     *lx++ = x_max;
  1403.     *ly++ = ay;
  1404.     return(TRUE);
  1405.     } else if (inrange(ax,x_min,x_max)) {    /* cross plotspace in y-direction */
  1406.     *lx++ = bx;
  1407.     *ly++ = y_min;
  1408.     *lx++ = bx;
  1409.     *ly++ = y_max;
  1410.     return(TRUE);
  1411.     } else
  1412.     return(FALSE);
  1413. }
  1414.  
  1415. /* double edge intersection algorithm */
  1416. /* Given two points, both outside the plot, return
  1417.  * the points where an edge of the plot intersects the line segment defined 
  1418.  * by the two points. There may be zero, one, two, or an infinite number
  1419.  * of intersection points. (One means an intersection at a corner, infinite
  1420.  * means overlaying the edge itself). We return FALSE when there is nothing
  1421.  * to draw (zero intersections), and TRUE when there is something to 
  1422.  * draw (the one-point case is a degenerate of the two-point case and we do 
  1423.  * not distinguish it - we draw it anyway).
  1424.  */
  1425. TBOOLEAN                /* any intersection? */
  1426. two_edge_intersect(points, i, lx, ly)
  1427.     struct coordinate GPHUGE *points; /* the points array */
  1428.     int i;                /* line segment from point i-1 to point i */
  1429.     double *lx, *ly;        /* lx[2], ly[2]: points where it crosses edges */
  1430. {
  1431.     /* global x_min, x_max, y_min, x_max */
  1432.     double ax = points[i-1].x;
  1433.     double ay = points[i-1].y;
  1434.     double bx = points[i].x;
  1435.     double by = points[i].y;
  1436.     double x, y;            /* possible intersection point */
  1437.     TBOOLEAN intersect = FALSE;
  1438.  
  1439.     if (by == ay) {
  1440.        /* horizontal line */
  1441.        /* y coord must be in range, and line must span both x_min and x_max */
  1442.        /* note that spanning x_min implies spanning x_max */
  1443.        if (inrange(by, y_min, y_max) && inrange(x_min, ax, bx)) {
  1444.           *lx++ = x_min;
  1445.           *ly++ = by;
  1446.           *lx++ = x_max;
  1447.           *ly++ = by;
  1448.           return(TRUE);
  1449.        } else
  1450.         return(FALSE);
  1451.     } else if (bx == ax) {
  1452.        /* vertical line */
  1453.        /* x coord must be in range, and line must span both y_min and y_max */
  1454.        /* note that spanning y_min implies spanning y_max */
  1455.        if (inrange(bx, x_min, x_max) && inrange(y_min, ay, by)) {
  1456.           *lx++ = bx;
  1457.           *ly++ = y_min;
  1458.           *lx++ = bx;
  1459.           *ly++ = y_max;
  1460.           return(TRUE);
  1461.        } else
  1462.         return(FALSE);
  1463.     }
  1464.  
  1465.     /* slanted line of some kind */
  1466.     /* there can be only zero or two intersections below */
  1467.  
  1468.     /* does it intersect y_min edge */
  1469.     if (inrange(y_min, ay, by)) {
  1470.        x = ax + (y_min-ay) * ((bx-ax) / (by-ay));
  1471.        if (inrange(x, x_min, x_max)) {
  1472.           *lx++ = x;
  1473.           *ly++ = y_min;
  1474.           intersect = TRUE;
  1475.        }
  1476.     }
  1477.     
  1478.     /* does it intersect y_max edge */
  1479.     if (inrange(y_max, ay, by)) {
  1480.        x = ax + (y_max-ay) * ((bx-ax) / (by-ay));
  1481.        if (inrange(x, x_min, x_max)) {
  1482.           *lx++ = x;
  1483.           *ly++ = y_max;
  1484.           intersect = TRUE;
  1485.        }
  1486.     }
  1487.  
  1488.     /* does it intersect x_min edge */
  1489.     if (inrange(x_min, ax, bx)) {
  1490.        y = ay + (x_min-ax) * ((by-ay) / (bx-ax));
  1491.        if (inrange(y, y_min, y_max)) {
  1492.           *lx++ = x_min;
  1493.           *ly++ = y;
  1494.           intersect = TRUE;
  1495.        }
  1496.     }
  1497.  
  1498.     /* does it intersect x_max edge */
  1499.     if (inrange(x_max, ax, bx)) {
  1500.        y = ay + (x_max-ax) * ((by-ay) / (bx-ax));
  1501.        if (inrange(y, y_min, y_max)) {
  1502.           *lx++ = x_max;
  1503.           *ly++ = y;
  1504.           intersect = TRUE;
  1505.        }
  1506.     }
  1507.  
  1508.     if (intersect)
  1509.      return(TRUE);
  1510.  
  1511.     /* It is possible for one or more of the [ab][xy] values to be -VERYLARGE.
  1512.     * If ax=bx=-VERYLARGE or ay=by=-VERYLARGE we have already returned
  1513.     * FALSE above.
  1514.     * Note that for ax=ay=-VERYLARGE or bx=by=-VERYLARGE we can do nothing.
  1515.     * Otherwise we fall through all the tests above. 
  1516.     * Handle them carefully here. As yet we have no way for them to be +VERYLARGE.
  1517.     */
  1518.     if (ax == -VERYLARGE) {
  1519.        if (ay != -VERYLARGE
  1520.           && inrange(by, y_min, y_max) && inrange(x_max, ax, bx)) {
  1521.           *lx++ = x_min;
  1522.           *ly = by;
  1523.           *lx++ = x_max;
  1524.           *ly = by;
  1525.           intersect = TRUE;
  1526.        }
  1527.     } else if (bx == -VERYLARGE) {
  1528.        if (by != -VERYLARGE
  1529.           && inrange(ay, y_min, y_max) && inrange(x_max, ax, bx)) {
  1530.           *lx++ = x_min;
  1531.           *ly = ay;
  1532.           *lx++ = x_max;
  1533.           *ly = ay;
  1534.           intersect = TRUE;
  1535.        }
  1536.     } else if (ay == -VERYLARGE) {
  1537.        /* note we know ax != -VERYLARGE */
  1538.        if (inrange(bx, x_min, x_max) && inrange(y_max, ay, by)) {
  1539.           *lx++ = bx;
  1540.           *ly = y_min;
  1541.           *lx++ = bx;
  1542.           *ly = y_max;
  1543.           intersect = TRUE;
  1544.        }
  1545.     } else if (by == -VERYLARGE) {
  1546.        /* note we know bx != -VERYLARGE */
  1547.        if (inrange(ax, x_min, x_max) && inrange(y_max, ay, by)) {
  1548.           *lx++ = ax;
  1549.           *ly = y_min;
  1550.           *lx++ = ax;
  1551.           *ly = y_max;
  1552.           intersect = TRUE;
  1553.        }
  1554.     }
  1555.  
  1556.     return(intersect);
  1557. }
  1558.  
  1559. /* Polar transform of all curves */
  1560. /* Original code by John Campbell (CAMPBELL@NAUVAX.bitnet) */
  1561. polar_xform (plots, pcount)
  1562.     struct curve_points *plots;
  1563.     int pcount;            /* count of curves in plots array */
  1564. {
  1565.      struct curve_points *this_plot;
  1566.      int curve;            /* loop var, for curves */
  1567.      register int i, p_cnt;    /* loop/limit var, for points */
  1568.      struct coordinate GPHUGE *pnts;    /* abbrev. for points array */
  1569.     double x, y;            /* new cartesian value */
  1570.     TBOOLEAN anydefined = FALSE;
  1571.     double d2r;
  1572.  
  1573.     if(angles_format == ANGLES_DEGREES){
  1574.         d2r = DEG2RAD;
  1575.     } else {
  1576.         d2r = 1.0;
  1577.     }
  1578.  
  1579. /*
  1580.     Cycle through all the plots converting polar to rectangular.
  1581.      If autoscaling, adjust max and mins. Ignore previous values.
  1582.     If not autoscaling, use the yrange for both x and y ranges.
  1583. */
  1584.     if (autoscale_ly) {
  1585.         x_min = VERYLARGE;
  1586.         y_min = VERYLARGE;
  1587.         x_max = -VERYLARGE;
  1588.         y_max = -VERYLARGE;
  1589.         autoscale_lx = TRUE;
  1590.     } else {
  1591.         x_min = y_min;
  1592.         x_max = y_max;
  1593.     }
  1594.     
  1595.     this_plot = plots;
  1596.     for (curve = 0; curve < pcount; this_plot = this_plot->next_cp, curve++) {
  1597.         p_cnt = this_plot->p_count;
  1598.         pnts = &(this_plot->points[0]);
  1599.  
  1600.     /*    Convert to cartesian all points in this curve. */
  1601.         for (i = 0; i < p_cnt; i++) {
  1602.             if (pnts[i].type != UNDEFINED) {
  1603.                  anydefined = TRUE;
  1604.                  /* modify points to reset origin and from degrees */
  1605.                  pnts[i].y -= rmin;
  1606.                  pnts[i].x *= d2r;
  1607.                  /* convert to cartesian coordinates */
  1608.                 x = pnts[i].y*cos(pnts[i].x);
  1609.                 y = pnts[i].y*sin(pnts[i].x);
  1610.                 pnts[i].x = x;
  1611.                 pnts[i].y = y;
  1612.                 if (autoscale_ly) {
  1613.                     if (x_min > x) x_min = x;
  1614.                     if (x_max < x) x_max = x;
  1615.                     if (y_min > y) y_min = y;
  1616.                     if (y_max < y) y_max = y;
  1617.                     pnts[i].type = INRANGE;
  1618.                 } else if(inrange(x, x_min, x_max) && inrange(y, y_min, y_max))
  1619.                   pnts[i].type = INRANGE;
  1620.                 else
  1621.                   pnts[i].type = OUTRANGE;
  1622.             }
  1623.         }    
  1624.     }
  1625.  
  1626.     if (autoscale_lx && anydefined && fabs(x_max - x_min) < zero) {
  1627.         /* This happens at least for the plot of 1/cos(x) (vertical line). */
  1628.         fprintf(stderr, "Warning: empty x range [%g:%g], ", x_min,x_max);
  1629.         if (x_min == 0.0) {
  1630.            x_min = -1; 
  1631.            x_max = 1;
  1632.         } else {
  1633.            x_min *= 0.9;
  1634.            x_max *= 1.1;
  1635.         }
  1636.         fprintf(stderr, "adjusting to [%g:%g]\n", x_min,x_max);
  1637.     }
  1638.     if (autoscale_ly && anydefined && fabs(y_max - y_min) < zero) {
  1639.         /* This happens at least for the plot of 1/sin(x) (horiz. line). */
  1640.         fprintf(stderr, "Warning: empty y range [%g:%g], ", y_min, y_max);
  1641.         if (y_min == 0.0) {
  1642.            y_min = -1;
  1643.            y_max = 1;
  1644.         } else {
  1645.            y_min *= 0.9;
  1646.            y_max *= 1.1;
  1647.         }
  1648.         fprintf(stderr, "adjusting to [%g:%g]\n", y_min, y_max);
  1649.     }
  1650. }
  1651.  
  1652. /* DRAW_YTICS: draw a regular tic series, y axis */
  1653. draw_ytics(start, incr, end)
  1654.         double start, incr, end; /* tic series definition */
  1655.         /* assume start < end, incr > 0 */
  1656. {
  1657.     double ticplace;
  1658.     int ltic;            /* for mini log tics */
  1659.     double lticplace;    /* for mini log tics */
  1660.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1661.  
  1662.     if (end == VERYLARGE)            /* for user-def series */
  1663.         end = max(y_min,y_max);
  1664.  
  1665.     /* limit to right side of plot */
  1666.     end = min(end, max(y_min,y_max));
  1667.  
  1668.     /* to allow for rounding errors */
  1669.     ticmin = min(y_min,y_max) - SIGNIF*incr;
  1670.     ticmax = max(y_min,y_max) + SIGNIF*incr;
  1671.     end = end + SIGNIF*incr; 
  1672.  
  1673.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1674.         if ( inrange(ticplace,ticmin,ticmax) )
  1675.             ytick(ticplace, yformat, incr, 1.0);
  1676.         if (is_log_y && incr == 1.0) {
  1677.             /* add mini-ticks to log scale ticmarks */
  1678.             int lstart, linc;
  1679.             if ((end - start) >= 10)
  1680.             {
  1681.             lstart = 10; /* No little ticks */
  1682.             linc = 5;
  1683.             }
  1684.             else if((end - start) >= 5)
  1685.             {
  1686.             lstart = 2; /* 4 per decade */
  1687.             linc = 3;
  1688.             }
  1689.             else
  1690.             {
  1691.             lstart = 2; /* 9 per decade */
  1692.             linc = 1;
  1693.             }
  1694.             for (ltic = lstart; ltic < (int)base_log_y; ltic += linc) {
  1695.                 lticplace = ticplace+log((double)ltic)/log_base_log_y;
  1696.                 if ( inrange(lticplace,ticmin,ticmax) )
  1697.                     ytick(lticplace, "\0", incr, 0.5);
  1698.             }
  1699.         }
  1700.     }
  1701. }
  1702.  
  1703. /* DRAW_XTICS: draw a regular tic series, x axis */
  1704. draw_xtics(start, incr, end)
  1705.         double start, incr, end; /* tic series definition */
  1706.         /* assume start < end, incr > 0 */
  1707. {
  1708.     double ticplace;
  1709.     int ltic;            /* for mini log tics */
  1710.     double lticplace;    /* for mini log tics */
  1711.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1712.  
  1713.     if (end == VERYLARGE)            /* for user-def series */
  1714.         end = max(x_min,x_max);
  1715.  
  1716.     /* limit to right side of plot */
  1717.     end = min(end, max(x_min,x_max));
  1718.  
  1719.     /* to allow for rounding errors */
  1720.     ticmin = min(x_min,x_max) - SIGNIF*incr;
  1721.     ticmax = max(x_min,x_max) + SIGNIF*incr;
  1722.     end = end + SIGNIF*incr; 
  1723.  
  1724.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1725.         if ( inrange(ticplace,ticmin,ticmax) )
  1726.             if(!polar || ticplace == start || ticplace == end) 
  1727.                 xtick(ticplace, xformat, incr, 1.0);
  1728.         if (is_log_x && incr == 1.0) {
  1729.             /* add mini-ticks to log scale ticmarks */
  1730.             int lstart, linc;
  1731.             if ((end - start) >= 10)
  1732.             {
  1733.             lstart = 10; /* No little ticks */
  1734.             linc = 5;
  1735.             }
  1736.             else if((end - start) >= 5)
  1737.             {
  1738.             lstart = 2; /* 4 per decade */
  1739.             linc = 3;
  1740.             }
  1741.             else
  1742.             {
  1743.             lstart = 2; /* 9 per decade */
  1744.             linc = 1;
  1745.             }
  1746.             for (ltic = lstart; ltic < (int)base_log_x; ltic += linc) {
  1747.                 lticplace = ticplace+log((double)ltic)/log_base_log_x;
  1748.                 if ( inrange(lticplace,ticmin,ticmax) )
  1749.                     xtick(lticplace, "\0", incr, 0.5);
  1750.             }
  1751.         }
  1752.     }
  1753. }
  1754.  
  1755. /* DRAW_SERIES_YTICS: draw a user tic series, y axis */
  1756. draw_series_ytics(start, incr, end)
  1757.         double start, incr, end; /* tic series definition */
  1758.         /* assume start < end, incr > 0 */
  1759. {
  1760.     double ticplace, place;
  1761.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1762.     double spacing = is_log_y ? log(incr)/log_base_log_y : incr;
  1763.  
  1764.     if (end == VERYLARGE)
  1765.         end = max(CheckLog(is_log_y, base_log_y, y_min),
  1766.               CheckLog(is_log_y, base_log_y, y_max));
  1767.     else
  1768.       /* limit to right side of plot */
  1769.       end = min(end, max(CheckLog(is_log_y, base_log_y, y_min),
  1770.                  CheckLog(is_log_y, base_log_y, y_max)));
  1771.  
  1772.     /* to allow for rounding errors */
  1773.     ticmin = min(y_min,y_max) - SIGNIF*incr;
  1774.     ticmax = max(y_min,y_max) + SIGNIF*incr;
  1775.     end = end + SIGNIF*incr; 
  1776.  
  1777.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1778.         place = (is_log_y ? log(ticplace)/log_base_log_y : ticplace);
  1779.         if ( inrange(place,ticmin,ticmax) )
  1780.          ytick(place, yformat, spacing, 1.0);
  1781.     }
  1782. }
  1783.  
  1784.  
  1785. /* DRAW_SERIES_XTICS: draw a user tic series, x axis */
  1786. draw_series_xtics(start, incr, end)
  1787.         double start, incr, end; /* tic series definition */
  1788.         /* assume start < end, incr > 0 */
  1789. {
  1790.     double ticplace, place;
  1791.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1792.     double spacing = is_log_x ? log(incr)/log_base_log_x : incr;
  1793.  
  1794.     if (end == VERYLARGE)
  1795.         end = max(CheckLog(is_log_x, base_log_x, x_min),
  1796.               CheckLog(is_log_x, base_log_x, x_max));
  1797.     else
  1798.       /* limit to right side of plot */
  1799.       end = min(end, max(CheckLog(is_log_x, base_log_x, x_min),
  1800.                  CheckLog(is_log_x, base_log_x, x_max)));
  1801.  
  1802.     /* to allow for rounding errors */
  1803.     ticmin = min(x_min,x_max) - SIGNIF*incr;
  1804.     ticmax = max(x_min,x_max) + SIGNIF*incr;
  1805.     end = end + SIGNIF*incr; 
  1806.  
  1807.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1808.         place = (is_log_x ? log(ticplace)/log_base_log_x : ticplace);
  1809.         if ( inrange(place,ticmin,ticmax) )
  1810.          xtick(place, xformat, spacing, 1.0);
  1811.     }
  1812. }
  1813. char GPFAR * GPFAR month[]={
  1814.     "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
  1815. };
  1816. draw_month_ytics()
  1817.     long l_tickplace,l_incr,l_end,m_calc;
  1818.  
  1819.     l_tickplace = (long)y_min;
  1820.     if((double)l_tickplace<y_min)l_tickplace++;
  1821.     l_end=(double)y_max;
  1822.     l_incr=(l_end-l_tickplace+1)/12;
  1823.     if(l_incr<1)l_incr=1;
  1824.     while(l_tickplace<=l_end)
  1825.     {
  1826.     m_calc = (l_tickplace-1)%12;
  1827.     if(m_calc<0)m_calc += 12;
  1828.     ytick((double)l_tickplace,month[m_calc],(double)l_incr,1.0);
  1829.     l_tickplace += l_incr;
  1830.     }
  1831. }
  1832. draw_month_xtics()
  1833. {
  1834.     long l_tickplace,l_incr,l_end,m_calc;
  1835.  
  1836.     l_tickplace = (long)x_min;
  1837.     if((double)l_tickplace<x_min)l_tickplace++;
  1838.     l_end=(double)x_max;
  1839.     l_incr=(l_end-l_tickplace+1)/12;
  1840.     if(l_incr<1)l_incr=1;
  1841.     while(l_tickplace<=l_end)
  1842.     {
  1843.     m_calc = (l_tickplace-1)%12;
  1844.     if(m_calc<0)m_calc += 12;
  1845.     xtick((double)l_tickplace,month[m_calc],(double)l_incr,1.0);
  1846.     l_tickplace += l_incr;
  1847.     }
  1848. }
  1849. char *day[]={
  1850.     "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
  1851. };
  1852. draw_day_ytics()
  1853.     long l_tickplace,l_incr,l_end,m_calc;
  1854.  
  1855.     l_tickplace = (long)y_min;
  1856.     if((double)l_tickplace<y_min)l_tickplace++;
  1857.     l_end=(double)y_max;
  1858.     l_incr=(l_end-l_tickplace+1)/14;
  1859.     if(l_incr<1)l_incr=1;
  1860.     while(l_tickplace<=l_end)
  1861.     {
  1862.     m_calc = l_tickplace%7;
  1863.     if(m_calc<0)m_calc += 7;
  1864.     ytick((double)l_tickplace,day[m_calc],(double)l_incr,1.0);
  1865.     l_tickplace += l_incr;
  1866.     }
  1867. }
  1868. draw_day_xtics()
  1869.     long l_tickplace,l_incr,l_end,m_calc;
  1870.  
  1871.     l_tickplace = (long)x_min;
  1872.     if((double)l_tickplace<x_min)l_tickplace++;
  1873.     l_end=(double)x_max;
  1874.     l_incr=(l_end-l_tickplace+1)/14;
  1875.     if(l_incr<1)l_incr=1;
  1876.     while(l_tickplace<=l_end)
  1877.     {
  1878.     m_calc = l_tickplace%7;
  1879.     if(m_calc<0)m_calc += 7;
  1880.     xtick((double)l_tickplace,day[m_calc],(double)l_incr,1.0);
  1881.     l_tickplace += l_incr;
  1882.     }
  1883. }
  1884. /* DRAW_SET_YTICS: draw a user tic set, y axis */
  1885. draw_set_ytics(list)
  1886.     struct ticmark *list;    /* list of tic marks */
  1887. {
  1888.     double ticplace;
  1889.     double incr = (y_max - y_min) / 10;
  1890.     /* global x_min, x_max, xscale, y_min, y_max, yscale */
  1891.  
  1892.     while (list != NULL) {
  1893.        ticplace = (is_log_y ? log(list->position)/log_base_log_y
  1894.                 : list->position);
  1895.        if ( inrange(ticplace, y_min, y_max)         /* in range */
  1896.           || NearlyEqual(ticplace, y_min, incr)    /* == y_min */
  1897.           || NearlyEqual(ticplace, y_max, incr))    /* == y_max */
  1898.         ytick(ticplace, list->label, incr, 1.0);
  1899.  
  1900.        list = list->next;
  1901.     }
  1902. }
  1903.  
  1904. /* DRAW_SET_XTICS: draw a user tic set, x axis */
  1905. draw_set_xtics(list)
  1906.     struct ticmark *list;    /* list of tic marks */
  1907. {
  1908.     double ticplace;
  1909.     double incr = (x_max - x_min) / 10;
  1910.     /* global x_min, x_max, xscale, y_min, y_max, yscale */
  1911.  
  1912.     while (list != NULL) {
  1913.        ticplace = (is_log_x ? log(list->position)/log_base_log_x
  1914.                 : list->position);
  1915.        if ( inrange(ticplace, x_min, x_max)         /* in range */
  1916.           || NearlyEqual(ticplace, x_min, incr)    /* == x_min */
  1917.           || NearlyEqual(ticplace, x_max, incr))    /* == x_max */
  1918.         xtick(ticplace, list->label, incr, 1.0);
  1919.  
  1920.        list = list->next;
  1921.     }
  1922. }
  1923.  
  1924. /* draw and label a y-axis ticmark */
  1925. ytick(place, text, spacing, ticscale)
  1926.         double place;                   /* where on axis to put it */
  1927.         char *text;                     /* optional text label */
  1928.         double spacing;         /* something to use with checkzero */
  1929.         double ticscale;         /* scale factor for tic mark (0..1] */
  1930. {
  1931.     register struct termentry *t = &term_tbl[term];
  1932.     char ticlabel[101];
  1933.     int ticsize = (int)((t->h_tic) * ticscale);
  1934.  
  1935.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  1936.     if (grid) {
  1937.            (*t->linetype)(-1);  /* axis line type */
  1938.            /* do not put a rectangular grid on a polar plot */
  1939.        if( !polar){
  1940.          (*t->move)(xleft, map_y(place));
  1941.          (*t->vector)(xright, map_y(place));
  1942.            } else {   /* put a circular grid for polar -- not clipped! */
  1943.              int i;
  1944.         (*t->move)(map_x(ZERO), map_y(place));
  1945.         for( i=0; i <= 360; i++)
  1946.            (*t->vector)( map_x(place*sin( (double) DEG2RAD*i)),
  1947.             map_y(place*cos( (double) DEG2RAD*i)) );
  1948.         }
  1949.        (*t->linetype)(-2); /* border linetype */
  1950.     }
  1951.     if (tic_in) {
  1952.       /* if polar plot, put the tics along the axes */
  1953.       if( polar){
  1954.            (*t->move)(map_x(ZERO),map_y(place));
  1955.            (*t->vector)(map_x(ZERO) + ticsize, map_y(place));
  1956.            (*t->move)(map_x(ZERO), map_y(place));
  1957.            (*t->vector)(map_x(ZERO) - ticsize, map_y(place));
  1958.      } else {
  1959.        (*t->move)(xleft, map_y(place));
  1960.            (*t->vector)(xleft + ticsize, map_y(place));
  1961.            (*t->move)(xright, map_y(place));
  1962.            (*t->vector)(xright - ticsize, map_y(place));
  1963.      }
  1964.     } else {
  1965.       if( polar){
  1966.            (*t->move)(map_x(ZERO), map_y(place));
  1967.            (*t->vector)(map_x(ZERO) - ticsize, map_y(place));
  1968.      }else{
  1969.            (*t->move)(xleft, map_y(place));
  1970.            (*t->vector)(xleft - ticsize, map_y(place));
  1971.      }
  1972.     }
  1973.  
  1974.     /* label the ticmark */
  1975.     if (text == NULL) 
  1976.      text = yformat;
  1977.     
  1978.     if( polar){
  1979.       (void) sprintf(ticlabel, text,
  1980.         CheckLog(is_log_y, base_log_y, fabs( place)+rmin));
  1981.       if ((*t->justify_text)(RIGHT)) {
  1982.        (*t->put_text)(map_x(ZERO)-(t->h_char),
  1983.                    map_y(place), ticlabel);
  1984.      } else {
  1985.        (*t->put_text)(map_x(ZERO)-(t->h_char)*(strlen(ticlabel)+1),
  1986.                    map_y(place), ticlabel);
  1987.      }
  1988.     } else {
  1989.     
  1990.       (void) sprintf(ticlabel, text, CheckLog(is_log_y, base_log_y, place));
  1991.       if ((*t->justify_text)(RIGHT)) {
  1992.        (*t->put_text)(xleft-(t->h_char),
  1993.                    map_y(place), ticlabel);
  1994.      } else {
  1995.        (*t->put_text)(xleft-(t->h_char)*(strlen(ticlabel)+1),
  1996.                    map_y(place), ticlabel);
  1997.      }
  1998.     }
  1999. }
  2000.  
  2001. /* draw and label an x-axis ticmark */
  2002. xtick(place, text, spacing, ticscale)
  2003.         double place;                   /* where on axis to put it */
  2004.         char *text;                     /* optional text label */
  2005.         double spacing;         /* something to use with checkzero */
  2006.         double ticscale;         /* scale factor for tic mark (0..1] */
  2007. {
  2008.     register struct termentry *t = &term_tbl[term];
  2009.     char ticlabel[101];
  2010.     int ticsize = (int)((t->v_tic) * ticscale);
  2011.  
  2012.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  2013.     if (grid) {
  2014.            (*t->linetype)(-1);  /* axis line type */
  2015.            if( !polar){  /* do not place a rectangular grid */
  2016.          (*t->move)(map_x(place), ybot);
  2017.          (*t->vector)(map_x(place), ytop);
  2018.            } else { /* angular lines only for start and stop */
  2019.          int i;
  2020.          for( i=0; i < 360; i+=10){
  2021.          (*t->move)(map_x(ZERO),map_y(ZERO) );
  2022.          (*t->vector)(map_x(-place*cos((double) DEG2RAD*i)),
  2023.              map_y(-place*sin( (double)DEG2RAD*i)));
  2024.          if( i%90 == 0){
  2025.              (void) sprintf(ticlabel, "%d", i);
  2026.          (*t->put_text)(map_x(-1.05*place*cos((double) DEG2RAD*i))
  2027.              +(t->h_char)*strlen(ticlabel)/2,
  2028.              map_y(-1.05*place*sin( (double)DEG2RAD*i))
  2029.                  , ticlabel);
  2030.          }
  2031.          }
  2032.            }
  2033.        (*t->linetype)(-2); /* border linetype */
  2034.     }
  2035.     if (tic_in) {
  2036.       if( polar){
  2037.            (*t->move)(map_x(place), map_y(ZERO));
  2038.            (*t->vector)(map_x(place), map_y(ZERO) + ticsize);
  2039.            (*t->move)(map_x(place), map_y(ZERO));
  2040.            (*t->vector)(map_x(place), map_y(ZERO) - ticsize);
  2041.      } else{
  2042.            (*t->move)(map_x(place), ybot);
  2043.            (*t->vector)(map_x(place), ybot + ticsize);
  2044.            (*t->move)(map_x(place), ytop);
  2045.            (*t->vector)(map_x(place), ytop - ticsize);
  2046.      }
  2047.     } else {
  2048.       if( polar){
  2049.            (*t->move)(map_x(place), map_y(ZERO));
  2050.            (*t->vector)(map_x(place), map_y(ZERO) - ticsize);
  2051.      }else{
  2052.            (*t->move)(map_x(place), ybot);
  2053.            (*t->vector)(map_x(place), ybot - ticsize);
  2054.      }
  2055.     }
  2056.     
  2057.     /* label the ticmark */
  2058.     if (text == NULL)
  2059.      text = xformat;
  2060.  
  2061.     if(polar){
  2062.       (void) sprintf(ticlabel, text, CheckLog(is_log_x, base_log_x, fabs(place)+rmin));
  2063.       if ((*t->justify_text)(CENTRE)) {
  2064.        (*t->put_text)(map_x(place),
  2065.                    map_y(ZERO)-(t->v_char), ticlabel);
  2066.      } else {
  2067.        (*t->put_text)(map_x(place)-(t->h_char)*strlen(ticlabel)/2,
  2068.                    map_y(ZERO)-(t->v_char), ticlabel);
  2069.      }
  2070.     }else{
  2071.  
  2072.       (void) sprintf(ticlabel, text, CheckLog(is_log_x, base_log_x, place));
  2073.       if ((*t->justify_text)(CENTRE)) {
  2074.        (*t->put_text)(map_x(place),
  2075.                    ybot-(t->v_char), ticlabel);
  2076.      } else {
  2077.        (*t->put_text)(map_x(place)-(t->h_char)*strlen(ticlabel)/2,
  2078.                    ybot-(t->v_char), ticlabel);
  2079.      }
  2080.     }
  2081. }
  2082.  
  2083. #endif /* THINK_C_2 */